using System;
using System.IO.Ports;
using System.Text;
using XBee.Communications;
using System.Reflection;

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class ExtensionAttribute : Attribute { }
}

namespace XBee.Library
{
    public delegate void ReciveDataDelegate(ICommunicationData data);

    public class XBEE : IDisposable
    {
        #region Members
        private readonly SerialPort _xbee;
        private int indexSentence = 0;
        private byte[] tempSentence = new byte[200];
        private ICommunicationData _frameType;
        #endregion

        #region Construcctor
        public XBEE(string port, ICommunicationData frameData)
        {
            _frameType = frameData;
            _xbee = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
            if (_xbee.IsOpen)
                _xbee.Close();
            _xbee.Open();
            _xbee.DataReceived += new SerialDataReceivedEventHandler(_xbee_DataReceived);
        }
        #endregion

        #region Internal Methods
        void _xbee_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int numc = 0;
            byte data;
            numc = _xbee.BytesToRead;

            if (numc > 0)
            {
                for (int i = 0; i < numc; i++)
                {	// Process bytes received
                    data = (byte)_xbee.ReadByte();
                    tempSentence[indexSentence] = data;
                    indexSentence++;

                    if (_frameType.IsSecuenceComplete(tempSentence))
                    {
                        string tempData = new string(Encoding.UTF8.GetChars(tempSentence));
                        OnReciveData(_frameType.Deserialize(tempData));
                        indexSentence = 0;
                        tempSentence = new byte[200];
                        continue;
                    }
                }
            }
        }
        #endregion

        #region Public Methods
        public void Write(ICommunicationData data)
        {
            byte[] _data = Encoding.UTF8.GetBytes(data.Serialize());
            _xbee.Write(_data, 0, _data.Length);
        }
        #endregion

        #region Public Events
        public event ReciveDataDelegate OnReciveData;
        #endregion

        #region IDisposable
        public void Dispose()
        {
            _xbee.Close();
            _xbee.Dispose();
        }
        #endregion
    }

    public static class Extensions
    {
        private static byte[] tempBuffer = new byte[1];
        public static byte ReadByte(this SerialPort port)
        {
            port.Read(tempBuffer, 0, 1);
            return tempBuffer[0];
        }
    }
}
